﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using EnumKeys;
using LitJson;
using Webapp;
using log4net;

namespace xundh.API.WF
{
    public class NodeOperate
    {
        private JsonData _nodes;
        private JsonData _lines;
        private JsonData _top;
        private JsonData _graph;
        private string _form;
        private JsonData _params;

        API.WF.WF_WorkFlows serviceWFFlows = new WF_WorkFlows();
        API.WF.WF_Items serviceWFItems = new WF_Items();
        API.WF.WF_Templates serviceWFTemplate = new WF_Templates();
        Model.WF_Templates _modelWFTemplates;
        private Model.WF_Items _modelWFItems;

        private ILog logger = LogManager.GetLogger("xundh.API.WF.NodeOperate"); 
        public Model.WF_Items ModelWFItems
        {
            get { return _modelWFItems; }
            set { _modelWFItems = value; }
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="ItemId"></param>
        public NodeOperate(int ItemId)
        {
            _modelWFItems = serviceWFItems.Query(ItemId);
            _modelWFTemplates = serviceWFTemplate.Query(_modelWFItems.TemplateId ?? 0);

            _graph = JsonMapper.ToObject(_modelWFTemplates.GraphJson);
            //Form也作为json对象处理
            _form = HttpContext.Current.Server.UrlDecode(_modelWFItems.Form);
            string _tempParams = HttpContext.Current.Server.UrlDecode(_modelWFItems.Params);
            _params = JsonMapper.ToObject(str2json(_tempParams));
            _lines = _graph["lines"];
            _nodes = _graph["nodes"];
            _top = getTopNode();
        }

        /// <summary>
        /// 启动，从第一个节点，找到下一个任务或会签节点，遇到某些节点要自动跳过
        /// </summary>
        public ServiceStateKeys Start()
        {
            JsonData firstManual = goNext(_top);
            if (firstManual == null)
            {
                //找不到，这个工作流有问题
                return ServiceStateKeys.HardErr;
            }
            return ServiceStateKeys.Success;
        }
        /// <summary>
        /// 操作一个节点
        /// </summary>
        public ServiceStateKeys Verify(string Suggest, int State)
        {
            //已经到了哪个WorkFlow了
            serviceWFFlows.Verify(_modelWFItems.NowWorkFlowId ?? 0, Suggest, State);
            //找到节点
            JsonData nowNode = getNodeByName(_modelWFItems.NowNodeName);
            if (nowNode == null)
            {
                //找不到，这个工作流有问题
                return ServiceStateKeys.HardErr;
            }
            if (State == (int)WFState.NotPass)
            {
                //执行驳回SQL
                executeSql("NodeBackSql", nowNode);
                return EnumKeys.ServiceStateKeys.PostBack;
            }
            //执行通过SQL
            executeSql("NodePassSql", nowNode);
            JsonData manual = goNext(nowNode);
            if (manual == null)
                return ServiceStateKeys.HardErr;
            else if (manual["type"].ToString() == "end")
                return ServiceStateKeys.NotInUse;//结束
            else
                return ServiceStateKeys.Success;
        }
        /// <summary>
        /// 递归 找下一节点
        /// </summary>
        /// <param name="nowNode"></param>
        /// <returns></returns>
        private JsonData goNext(JsonData nowNode)
        {
            //zhaodao next
            JsonData line = null;
            if (nowNode["type"].ToString() == "fork")
            {
                //条件解析，找到相应line
                List<JsonData> lines = getLinesByNode(nowNode);
                foreach (JsonData templine in lines)
                {
                    string ConditionParam = "";// templine["ConditionParam"].ToString();
                    string ConditionOper = "";
                    string ConditionValue = "";
                    string actualvalue = "";
                    try
                    {
                        ConditionParam = templine["ConditionParam"].ToString();
                        ConditionOper = templine["ConditionOper"].ToString();
                        ConditionValue = templine["ConditionValue"].ToString();
                        //首先找系统变量
                        actualvalue = getSystemValue(ConditionParam, "", ModelWFItems.AddUserId ?? 0);
                        //如果没有，到提交变量里找
                        if (actualvalue == "")
                            actualvalue = _params[ConditionParam].ToString();
                    }
                    catch (Exception)
                    {
                        logger.Error(templine["name"].ToString() + "节点问题。");
                        actualvalue = "";
                    }

                    //如果是要获取系统变量

                    bool isTrue = false;
                    switch (ConditionOper)
                    {
                        case "==":
                            isTrue = (actualvalue == ConditionValue);
                            break;
                        case "!=":
                            isTrue = (actualvalue != ConditionValue);
                            break;
                        case ">":
                            if (StringUtil.isDate(actualvalue) && StringUtil.isDate(ConditionValue))
                                isTrue = (DateTime.Parse(actualvalue) > DateTime.Parse(ConditionValue));
                            else
                                isTrue = (StringUtil.GetFloatValue(actualvalue) > StringUtil.GetFloatValue(ConditionValue));
                            break;
                        case ">=":
                            if (StringUtil.isDate(actualvalue) && StringUtil.isDate(ConditionValue))
                                isTrue = (DateTime.Parse(actualvalue) >= DateTime.Parse(ConditionValue));
                            else
                                isTrue = (StringUtil.GetFloatValue(actualvalue) >= StringUtil.GetFloatValue(ConditionValue));
                            break;
                        case "<":
                            if (StringUtil.isDate(actualvalue) && StringUtil.isDate(ConditionValue))
                                isTrue = (DateTime.Parse(actualvalue) < DateTime.Parse(ConditionValue));
                            else
                                isTrue = (StringUtil.GetFloatValue(actualvalue) < StringUtil.GetFloatValue(ConditionValue));
                            break;
                        case "<=":
                            if (StringUtil.isDate(actualvalue) && StringUtil.isDate(ConditionValue))
                                isTrue = (DateTime.Parse(actualvalue) <= DateTime.Parse(ConditionValue));
                            else
                                isTrue = (StringUtil.GetFloatValue(actualvalue) <= StringUtil.GetFloatValue(ConditionValue));
                            break;
                        case "like":
                            isTrue = actualvalue.IndexOf(ConditionValue) > -1;
                            break;
                        case "not like":
                            isTrue = actualvalue.IndexOf(ConditionValue) < 0;
                            break;
                        default:
                            break;

                    }
                    if (isTrue)
                    {
                        line = templine;
                        break;
                    }
                }
            }
            else
            {
                //直接找到line
                line = getLinesByNode(nowNode)[0];
            }
            if (line == null)
            {//没有下级了
                return null;
            }
            JsonData nextNode = getNodeByLine(line);
            string[] manual = new string[] { "chat", "会签", "join", "task" };
            string[] skip = new string[] { "fork", "node" };
            string nextNodeType = nextNode["type"].ToString();
            bool useForVerify = nextNodeType == "chat";

            if (nextNodeType == "end")
            {
                //结束
                return nextNode;
            }
            string userids = "", users = "";
            if (nextNodeType != "fork")//分支直接向下
            {
                //获取用户列表
                xundh.API.RBAC.RBAC_Users serviceUsers = new RBAC.RBAC_Users();
                string NodeSpecifyType = "", NodeSpecifyTypeValue = "";
                try
                {
                    NodeSpecifyType = nextNode["NodeSpecifyType"].ToString();
                    NodeSpecifyTypeValue = nextNode["NodeSpecifyTypeValue"].ToString();
                }
                catch (Exception)
                {
                    logger.Error(NodeSpecifyType + NodeSpecifyTypeValue + "有问题。");
                }
                JsonTable jtSpecifyUsers = serviceUsers.GetListsBySpecifyUserType(
                    StringUtil.GetIntValue(NodeSpecifyType), NodeSpecifyTypeValue, useForVerify);
                if (jtSpecifyUsers != null)
                {
                    foreach (DataRow dr in jtSpecifyUsers.Table.Rows)
                    {
                        userids = userids.ItemAdd(dr["UserId"].ToString());
                        users = users.ItemAdd(dr["UserName"].ToString());
                    }
                    userids = userids.Trim(',');
                    users = users.Trim(',');
                }
            }
            if (manual.Contains(nextNodeType))
            {
                if (userids == "")
                {
                    //没有找到对应的人，寻找下一节点
                    return goNext(nextNode);
                }
                //生成WorkFlow记录
                int WorkFlowId = serviceWFFlows.Add(0, _modelWFItems.ItemId, 0, nextNode["name"].ToString(),
                    nextNode["type"].ToString(), userids, users, false);
                //执行节点到达SQL

                executeSql("NodeBeforeSql", nextNode);

                _modelWFItems.NowNodeName = nextNode["name"].ToString();
                _modelWFItems.NowWorkFlowId = WorkFlowId;
                _modelWFItems.NowToUsers = users;
                _modelWFItems.NowToUserIds = userids;
                //处理allids allnames
                _modelWFItems.SpecifyNames = _modelWFItems.SpecifyNames.ItemAdd(users);
                _modelWFItems.SpecifyIds = _modelWFItems.SpecifyIds.ItemAdd(userids);

                return nextNode;//手工操作节点
            }
            else if (skip.Contains(nextNodeType))
            {
                //生成自动审批记录
                if (userids != "")
                {
                    int WorkFlowId = serviceWFFlows.Add(0, _modelWFItems.ItemId, 0, nextNode["name"].ToString(),
                        nextNode["type"].ToString(), userids, users, true);
                    //执行节点到达SQL
                    executeSql("NodeBeforeSql", nextNode);
                    //执行节点完成SQL
                    executeSql("NodePassSql", nextNode);
                    _modelWFItems.NowNodeName = nextNode["name"].ToString();
                    _modelWFItems.NowWorkFlowId = WorkFlowId;
                    _modelWFItems.NowToUsers = users;
                    _modelWFItems.NowToUserIds = userids;
                    //处理allids allnames
                    _modelWFItems.SpecifyNames = _modelWFItems.SpecifyNames.ItemAdd(users);
                    _modelWFItems.SpecifyIds = _modelWFItems.SpecifyIds.ItemAdd(userids);
                }
                return goNext(nextNode); //自动节点，再找下一级
            }
            else
                return nextNode;//end的情况
        }


        /// <summary>
        /// 获取某个node的向下lines
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private List<JsonData> getLinesByNode(JsonData node)
        {
            //line.Sign是
            if (_lines.Count == 0) return null;
            List<JsonData> results = new List<JsonData>();
            for (int i = 0; i < _lines.Count; i++)
            {
                string line_key = _lines[i]["from"].ToString();
                JsonData temp_node = _nodes[line_key];
                if (temp_node == node)
                {
                    results.Add(_lines[i]);
                }
            }
            return results;
        }
        /// <summary>
        /// 获取某个line的下级node
        /// </summary>
        /// <returns></returns>
        private JsonData getNodeByLine(JsonData line)
        {
            if (_nodes.Count == 0) return null;
            string key = line["to"].ToString();
            return _nodes[key];
        }
        /// <summary>
        /// 找到起始节点
        /// </summary>
        /// <returns></returns>
        private JsonData getTopNode()
        {
            if (_nodes.Count == 0) return null;
            JsonData result = null;
            for (int i = 0; i < _nodes.Count; i++)
            {
                if (_nodes[i]["type"].ToString() == "start round")
                {
                    result = _nodes[i];
                    break;
                }
            }
            return result;
        }
        /// <summary>
        ///从name找某个节点
        /// </summary>
        /// <returns></returns>
        private JsonData getNodeByName(string name)
        {
            if (_nodes.Count == 0) return null;
            JsonData result = null;
            for (int i = 0; i < _nodes.Count; i++)
            {
                if (_nodes[i]["name"].ToString() == name)
                {
                    result = _nodes[i];
                    break;
                }
            }
            return result;
        }

        private string str2json(string str)
        {
            var result = "{";
            string[] oneitem = str.Split('&');
            foreach (string item in oneitem)
            {
                if (item.Trim() == "") continue;
                string[] v = item.Split('=');
                result += "'" + v[0] + "':";
                if (v.Count() == 2)
                    result += "'" + v[1] + "'";
                else
                    result += "''";
                result += ",";
            }
            result = result.TrimEnd(',') + "}";
            return result;
        }
        /// <summary>
        /// 执行sql
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        private void executeSql(string key, JsonData node)
        {
            string sql = "";
            try
            {
                sql = node[key].ToString();
            }
            catch (Exception)
            {

            }
            sql = StringUtil.GetNullToString(sql).Trim();
            if (sql == "") return;
            Regex reg = new Regex(@"\<\%#(?<segment>[a-zA-Z_\.]*?)\%\>");
            MatchCollection matches = reg.Matches(sql); ;
            foreach (Match m in matches)
            {
                string param = m.Groups["segment"].ToString();
                string newvalue;
                newvalue = getSystemValue(param, "", _modelWFItems.AddUserId ?? 0);

                //尝试从客户端参数获取
                if (newvalue == "")
                {
                    try { newvalue = StringUtil.GetNullToString(HttpContext.Current.Request[param]); }
                    catch (Exception) { }
                }
                if (newvalue == "")
                {
                    try { newvalue = _params[param].ToString(); }
                    catch (Exception) { }
                }
                sql = sql.Replace(m.Groups[0].ToString(), newvalue);
            }
            logger.Error(_modelWFItems.ItemId.ToString() + " " + sql);
            BLL.BasePager bllP = new BLL.BasePager();
            bllP.GetGPager(sql);
        }

        /// <summary>
        /// 按字符串返回与某用户相关的变量值
        /// </summary>
        /// <param name="ConditionParam"></param>
        /// <param name="DefaultValue"></param>
        /// <returns></returns>
        private string getSystemValue(string ConditionParam, string DefaultValue, int UserId)
        {   //以下与项目相关
            RBAC.RBAC_Users serviceRBACUsers = new RBAC.RBAC_Users();
            Model.RBAC_Users m = serviceRBACUsers.Query(UserId);
            Org.Org_Departs serviceOrgDeparts = new Org.Org_Departs();
            Model.RBAC_Users U = (Model.RBAC_Users)HttpContext.Current.Session[EnumKeys.SessionKey.USER];
            string[] commons = new string[] { "USERID", "POSTID", "POSTNAME", "USERNAME", "COPID", 
                "COPNAME", "DEPARTNAME", "DEPARTID", "SEX", "ENTRYTIME", 
                "_modelWFItems.AddUserId","_modelWFItems.ItemId","_modelWFItems.AddTime","U_USERID","U_USERNAME","U_DEPARTID",
                "U_DEPARTNAME","NOW","IP"
            };
            string actualvalue = "";
            if (commons.Contains(ConditionParam))
            {
                switch (ConditionParam)
                {
                    case "USERID":
                        actualvalue = m.UserId.ToString();
                        break;
                    case "POSTID":
                        actualvalue = m.PostId.ToString();
                        break;
                    case "POSTNAME":
                        Org.Org_Posts serviceOrgPosts = new Org.Org_Posts();
                        actualvalue = serviceOrgPosts.Query(m.PostId ?? 0).PostName;
                        break;
                    case "USERNAME":
                        actualvalue = m.UserName;
                        break;
                    case "DEPARTNAME":
                        actualvalue = serviceOrgDeparts.Query(m.DepartId ?? 0).DepartName;
                        break;
                    case "DEPARTID":
                        actualvalue = m.DepartId.ToString();
                        break;
                    case "SEX":
                        actualvalue = (m.UserSex ?? 0) == 0 ? "女" : "男";
                        break;
                    case "ENTRYTIME":
                        actualvalue = m.AddTime.ToString();
                        break;
                    case "_modelWFItems.AddUserId"://不用了，使用USERID
                        actualvalue = _modelWFItems.AddUserId.ToString();
                        break;
                    case "_modelWFItems.ItemId":
                        actualvalue = _modelWFItems.ItemId.ToString();
                        break;
                    case "_modelWFItems.AddTime":
                        actualvalue = _modelWFItems.AddTime.ToString();
                        break;
                    case "U_USERID":
                        actualvalue = U.UserId.ToString();
                        break;
                    case "U_USERNAME":
                        actualvalue = U.UserName;
                        break;
                    case "U_DEPARTID":
                        actualvalue = U.DepartId.ToString();
                        break;
                    case "U_DEPARTNAME":
                        actualvalue = serviceOrgDeparts.Query(U.DepartId ?? 0).DepartName;
                        break;
                    case "NOW":
                        actualvalue = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
                        break;
                    case "IP":
                        actualvalue = HttpContext.Current.Request.UserHostAddress;
                        break;
                }
                return actualvalue;
            }
            else
                return DefaultValue;
        }
    }
}
